package bitmap;

import global.Convert;
import global.GlobalConst;
import global.PageId;

import java.io.IOException;

import diskmgr.Page;

public class BMPage extends Page implements GlobalConst {
	
	  public static final int SIZE_OF_SLOT = 4;
	  public static final int DPFIXED =  4 * 2  + 3 * 4;
	  
	  public static final int SLOT_CNT = 0;
	  public static final int USED_PTR = 2;
	  public static final int FREE_SPACE = 4;
	  public static final int TYPE = 6;
	  public static final int PREV_PAGE = 8;
	  public static final int NEXT_PAGE = 12;
	  public static final int CUR_PAGE = 16;
	  public static int NUMBER_OF_BYTES = 0;
	  
	  /**
	   * offset of first used byte by data records in data[]
	   */
	  private    short     usedPtr;   
	  
	  /**
	   * number of bytes free in data[]
	   */
	  private    short     freeSpace;  
	  
	  /**
	   * backward pointer to data page
	   */
	  private    PageId   prevPage = new PageId(); 
	  
	  /**
	   * forward pointer to data page
	   */
	  private   PageId    nextPage = new PageId();  
	  
	  /**
	   *  page number of this page
	   */
	  protected    PageId    curPage = new PageId();   
	  
	  public BMPage(){
	  }
	  
	  public BMPage(Page page){
		  data = page.getpage();
	  }
	  
	  /**
	   * returns the amount of available space on the page.
	   * @return  the amount of available space on the page
	   * @exception  IOException I/O errors
	   */  
	  public int available_space()  
	    throws IOException
	    {
	      freeSpace = Convert.getShortValue (FREE_SPACE, data);
	      return (freeSpace);
	    }
	  
	  /**      
	   * Determining if the page is empty
	   * @return true if the BMPage is has no records in it, false otherwise  
	   * @exception  IOException I/O errors
	   */
	  public boolean empty() throws IOException
	    {
	      if(data.length == 0){
	    	  return true;  
	      }else{
	    	  return false;
	      }
	    }
	  
	  /**
	   * Constructor of class BMPage
	   * initialize a new page
	   * @param	pageNo	the page number of a new page to be initialized
	   * @param	apage	the Page to be initialized 
	   * @see		Page
	   * @exception IOException I/O errors
	   */
	  
	  
	  public void init(PageId pageNo, Page apage) throws IOException
	    {
	      data = apage.getpage();
	      
	      curPage.pid = pageNo.pid;
	      Convert.setIntValue (curPage.pid, CUR_PAGE, data);
	      
	      nextPage.pid = prevPage.pid = INVALID_PAGE;
	      Convert.setIntValue (prevPage.pid, PREV_PAGE, data);
	      Convert.setIntValue (nextPage.pid, NEXT_PAGE, data);
	      
	      usedPtr = (short) (DPFIXED + 1);  // offset in data array (grow backwards)
	      Convert.setShortValue (usedPtr, USED_PTR, data);
	      
	      freeSpace = (short) (MAX_SPACE - DPFIXED);    // amount of space available
	      Convert.setShortValue (freeSpace, FREE_SPACE, data);
	      
	    }
	  
	  /**
	   * Constructor of class BMPage
	   * open a existed bmpage
	   * @param  apage   a page in buffer pool
	   */
	  
	  public void openBMpage(Page apage)
	    {
	      data = apage.getpage();
	    }
	  
	  /**
	   * @return	PageId of previous page
	   * @exception IOException I/O errors
	   */
	  public PageId getPrevPage()   
	    throws IOException 
	    {
	      prevPage.pid =  Convert.getIntValue (PREV_PAGE, data);
	      return prevPage;
	    }
	  
	  /**
	   * sets value of prevPage to pageNo
	   * @param       pageNo  page number for previous page
	   * @exception IOException I/O errors
	   */
	  public void setPrevPage(PageId pageNo)
	    throws IOException
	    {
	      prevPage.pid = pageNo.pid;
	      Convert.setIntValue (prevPage.pid, PREV_PAGE, data);
	    }
	  
	  /**
	   * @return     page number of next page
	   * @exception IOException I/O errors
	   */
	  public PageId getNextPage()
	    throws IOException
	    {
	      nextPage.pid =  Convert.getIntValue (NEXT_PAGE, data);    
	      return nextPage;
	    }
	  
	  /**
	   * sets value of nextPage to pageNo
	   * @param	pageNo	page number for next page
	   * @exception IOException I/O errors
	   */
	  public void setNextPage(PageId pageNo)   
	    throws IOException
	    {
	      nextPage.pid = pageNo.pid;
	      Convert.setIntValue (nextPage.pid, NEXT_PAGE, data);
	    }
	  
	  /**
	   * @return 	page number of current page
	   * @exception IOException I/O errors
	   */
	  public PageId getCurPage() 
	    throws IOException
	    {
	      curPage.pid =  Convert.getIntValue (CUR_PAGE, data);
	      return curPage;
	    }
	  
	  /**
	   * sets value of curPage to pageNo
	   * @param	pageNo	page number for current page
	   * @exception IOException I/O errors
	   */
	  public void setCurPage(PageId pageNo)   
	    throws IOException
	    {
	      curPage.pid = pageNo.pid;
	      Convert.setIntValue (curPage.pid, CUR_PAGE, data);
	    }
	  
	  /**
	   * @return byte array
	   */
	  public byte [] getBMpageArray()
	    {
	      return data;
	    } 
	  
	  /**
	   * @return byte array
	 * @throws IOException 
	   */
	  public void writeBMPageArray(byte[] record) throws IOException{
		  // insert data onto the data page
		  usedPtr = Convert.getShortValue(USED_PTR, data);
		  System.arraycopy(record, 0, data, usedPtr, record.length);
		  usedPtr +=  record.length;
		  Convert.setShortValue (usedPtr, USED_PTR, data);

			// increase freespace by size of hole
		  freeSpace = Convert.getShortValue(FREE_SPACE, data);
		  freeSpace -= record.length;  
		  Convert.setShortValue (freeSpace, FREE_SPACE, data);
		}
	  
}
